package com.android.launcher3.util;

import android.app.AlarmManager;
import android.app.Application;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Looper;
import android.os.Process;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Calendar;

/**
 * Author:Hzc
 * Created on 2021/1/7
 */
public class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

    private static UncaughtExceptionHandler INSTANCE;

    public static void catchCrash(Application application) {
        if (INSTANCE == null) {
            INSTANCE = new UncaughtExceptionHandler(application);
        }
    }

    public static void catchCrash(Application application, @NonNull String path) {
        if (INSTANCE == null) {
            INSTANCE = new UncaughtExceptionHandler(application, path);
        } else {
            INSTANCE.CRASH_FILE_PATH = path;
        }
    }

    @Nullable
    private final Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
    private final String TAG = "UncaughtExceptionHandler";
    @NonNull
    private final Application APP;
    @NonNull
    private String CRASH_FILE_PATH;


    private UncaughtExceptionHandler(@NonNull Application app) {
        this(app, app.getFilesDir() + File.separator + "crash.txt");
    }

    private UncaughtExceptionHandler(@NonNull Application app, @NonNull String path) {
        this.APP = app;

        //文件夹路径
        CRASH_FILE_PATH = path;

        defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);

        initParams();
    }

    private void initParams() {

    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        if (e != null) {
            if (handleException(t, e)) {
                showTips(t, e);
                //一秒后重启
                return;
            }
            e.printStackTrace();
        }

        if (defaultUncaughtExceptionHandler != null) {
            defaultUncaughtExceptionHandler.uncaughtException(t, e);
        }
    }

    private void showTips(final Thread t, final Throwable e) {
        //检查是否有“显示在其它应用上层”的权限

        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();


                Toast.makeText(APP, "开了个小差", Toast.LENGTH_LONG).show();

                Looper.loop();
            }
        }).start();

        try {
            Thread.sleep(2000);
        } catch (Exception ignored) {
        }
//        prepareRestartApp(APP, 1000);
        Process.killProcess(Process.myPid());
//            System.exit(1);
    }

    private boolean handleException(@Nullable Thread t, @NonNull Throwable throwable) {
        //保存错误日志
        return saveError(t, throwable);
    }

    private boolean saveError(@Nullable Thread t, @NonNull Throwable throwable) {
        String threadMsg = null;
        if (t != null) {
            threadMsg = t.toString();
//            log(threadMsg);
        }
        String throwableMsg = getThrowableString(throwable);
        StringBuilder builder = new StringBuilder();
        Calendar calendar = Calendar.getInstance();
        builder.append(calendar.get(Calendar.YEAR)).append("年")
                .append(calendar.get(Calendar.MONTH) + 1).append("月")
                .append(calendar.get(Calendar.DAY_OF_MONTH)).append("日  ")
                .append(calendar.get(Calendar.HOUR_OF_DAY)).append(":")
                .append(calendar.get(Calendar.MINUTE)).append(":")
                .append(calendar.get(Calendar.SECOND)).append("  ")

                .append("==>>\n");
        builder.append(threadMsg).append("\n")
                .append(throwableMsg).append("\n\n");
        String error = builder.toString();

//        log(error);
        int fileSize = FileTools.getFileSizeByFullPath(CRASH_FILE_PATH);
        boolean append = fileSize < 1024 * 1024;

        return FileTools.writeText(CRASH_FILE_PATH, error, append);
    }

    @NonNull
    private String getThrowableString(@Nullable Throwable t) {
        if (t == null) return "";

//        StringBuilder msg = new StringBuilder(t.toString());
//        StackTraceElement[] stackTrace = t.getStackTrace();
//        for (StackTraceElement element : stackTrace) {
//            msg.append("\n").append(element);
//        }
//        return msg.toString();
        Writer writer = new StringWriter();
        PrintWriter pw = new PrintWriter(writer);
        t.printStackTrace(pw);
        pw.close();
        return writer.toString();
    }

    private void log(String text) {
        Logger.e(TAG, text);
    }

    /**
     * @param timeDelay 延迟重启时间
     */
    public static boolean prepareRestartApp(@NonNull Application app, long timeDelay) {
        try {
            Intent intent = app.getPackageManager().getLaunchIntentForPackage(app.getPackageName());
            PendingIntent restartIntent = PendingIntent.getActivity(app, 0, intent, 0);
            AlarmManager mgr = (AlarmManager) app.getSystemService(Context.ALARM_SERVICE);

            mgr.set(AlarmManager.RTC, timeDelay, restartIntent);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}
